package com.lijin.batchsys.framework.common;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.springframework.util.Assert;

import com.lijin.batchsys.framework.dao.model.BatchExecLogDetail;
import com.lijin.batchsys.framework.dao.model.JobInfo;
import com.lijin.batchsys.framework.dao.model.StepInfo;
import com.lijin.batchsys.framework.enums.BatchPageTable;
import com.lijin.batchsys.framework.enums.BatchRunType;
import com.lijin.batchsys.framework.enums.ErrBatchHandleMode;
import com.lijin.batchsys.framework.enums.RunningMode;
import com.lijin.batchsys.framework.enums.RunningStatus;
import com.lijin.batchsys.framework.schedule.RunPeriod;

public class BatchUtil {
	
	private static final String DATE_PARTTEN_8 = "yyyyMMdd";
	private static final String DATE_PARTTEN_14 = "yyyyMMddHHmmss";
	private static final String DATE_PARTTEN_17 = "yyyyMMdd HH:mm:ss";

	
	/**
	 * 求指定日期的下一天
	 * @param bh_date
	 * @return
	 */
	public static String nextDay(Date date) {
		Assert.notNull(date, "参数不能为null");
		return addDays(date, 1); 
	}

	/**
	 * 求指定日期的前一天
	 * @param date
	 * @return
	 */
	public static String preDay(Date date) {
		Assert.notNull(date, "参数不能为null");
		return addDays(date, -1);
	}
	
	/**
	 * 将制定的日期增加指定的天数
	 * @param date
	 * @param d
	 * @return
	 */
	private static String addDays(Date date, int d) {
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_PARTTEN_8);
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.DAY_OF_YEAR, d);
		return formatter.format(c.getTime());
	}

	/**
	 * 通过字符串返回Date类型的日期yyyyMMdd格式
	 * @param dateStr8
	 * @return
	 */
	public static Date parse(String dateStr8) {
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_PARTTEN_8);
		Date date = null;
		try {
			date = formatter.parse(dateStr8);
		} catch (ParseException e) {
			throw new BatchSysException("无法解析传入的日期字符串【" + dateStr8 + "】", e);
		}
		return date;
	}

	/**
	 * 通过Date类型日期返回字符串类型的日期
	 * @param date
	 * @return
	 */
	public static String formatDateTo8Str(Date date) {
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_PARTTEN_8);
		return formatter.format(date);
	}
	
	/**
	 * 通过Date类型日期返回字符串类型的日期
	 * @param date
	 * @return
	 */
	public static String formatDateTo17Str(Date date) {
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_PARTTEN_17);
		return formatter.format(date);
	}
	
	/**
	 * 将异常栈信息转为字符串
	 * @param t
	 * @return
	 */
	public static String printExceptionStack(Throwable t) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		PrintStream ps = new PrintStream(baos);
		t.printStackTrace(ps);
		String errMessage = baos.toString();
		
		if (errMessage != null && exceptionLength(errMessage)  > BatchSysConstants.ErrMessageLength) {
			errMessage = getExcStr(errMessage, BatchSysConstants.ErrMessageLength);
		}
		
		return errMessage;
	}
	
	/**
	 * 返回指定时间的yyyyMMddHHmmss格式字符串
	 * @return
	 */
	public static String formatTimeStamp(Date date) {
		Assert.notNull(date);
		SimpleDateFormat sdf = new SimpleDateFormat(DATE_PARTTEN_14);
		return sdf.format(date);
	}
	
	/**
	 * 获得系统当前时间
	 */
	public static String getCurrDate() {
	    SimpleDateFormat formater = new SimpleDateFormat(DATE_PARTTEN_8);
	    return formater.format(new Date());
	}
	
	/**
	 * 获得异常的长度（含中文） 
	 */
	private static int exceptionLength(String   value){
		if (value == null)
			return 0;

		StringBuffer buff = new StringBuffer(value);
		int length = 0;
		String stmp;
		for (int i = 0; i < buff.length(); i++) {
			stmp = buff.substring(i, i + 1);
			try {
				stmp = new String(stmp.getBytes("UTF-8"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			
			length += stmp.getBytes().length;

		}
		return length;
	}
	
	
	/**
	 * 获得包含中文的异常信息,进行了截取
	 * @param args
	 */
	private static String getExcStr(String oldStr, int maxLength){
		
		if (oldStr == null) return null;
		//根据长度取得对应的字符串	
		String strCache = oldStr.substring(0, maxLength);
		//对该字符串进行非英文过滤，存入数据库中。DB2中中文占3个字符
		StringBuffer buff = new StringBuffer(strCache);
		String stmp;
		for (int i = 0; i < buff.length(); i++) {
			stmp = buff.substring(i, i + 1);
			try {
				stmp = new String(stmp.getBytes("UTF-8"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		    //有出现非英文字符
			if(stmp.getBytes().length > 1){
				maxLength -=2;  //长度再减2
			}

		}
		//获得过滤好的字符串，存入数据库中
		strCache = strCache.substring(0, maxLength);
		return strCache;
	}
	
	/** 
	 *  给发生异常的Step添加操作功能
	 *  
	 *  RESTART_BATCH("0", "重新执行整个批次"),
	 *  IGNORE_STEP_GO_ON("1", "忽略该步骤继续执行"),
	 *  RESTART_STEP_GO_ON("2", "重新执行该步骤继续执行"),
	 *  RESTART_SINGLE_STEP("3", "只重新执行该步骤"),
	 *  RESTART_SINGLE_JOB("4", "只重新执行所属的任务");
	 * @param runningMode 
	 * 
	 */
	public static void buildOperate(List<BatchExecLogDetail> detailList, RunningMode batchRunningMode) {
		
		Map<String, String> operateButtons ;
		//功能名称
		String nameKey = null;   
		//功能名称对应的方法名编号
		String functionCode = null;
		
		for(BatchExecLogDetail detail : detailList){
		    operateButtons = new TreeMap<String, String>();
		    StepInfo step = BatchCache.getInstance().getStepInfo(detail.getBatchNo(), detail.getJobNo(), detail.getStepNo());
		    JobInfo job = BatchCache.getInstance().getJobInfo(detail.getBatchNo(), detail.getJobNo());
		    
		    if (RunningStatus.FAILED.getCode().equals(detail.getStatus())) {
		    	
			    /** 运行任务类型为单个步骤--step**/
			    if(batchRunningMode == RunningMode.START_SINGLE_STEP){
					nameKey = ErrBatchHandleMode.RESTART_SINGLE_STEP.getDesc();
					functionCode = ErrBatchHandleMode.RESTART_SINGLE_STEP.getCode();
					operateButtons.put(nameKey, functionCode);
					//添加到Bean中
				    detail.setOperateButtons(operateButtons);
					break;
			    }
			    
			    /** 运行任务类型为批次任务--job**/
			    if(batchRunningMode == RunningMode.START_BATCH){//job类型不添加RESTART_BATCH
					//----重拉整个批次
					nameKey = ErrBatchHandleMode.RESTART_BATCH.getDesc();
					functionCode = ErrBatchHandleMode.RESTART_BATCH.getCode();
					operateButtons.put(nameKey, functionCode);
			    }
			    
			    /** 运行任务类型为定时批次--batch**/
				//任务发生异常中断批次
				if(job.canSkip() || job.isConcurrent()){//可跳过 或 并行
					
					//----只执行该步骤
					nameKey = ErrBatchHandleMode.RESTART_SINGLE_STEP.getDesc();
					functionCode = ErrBatchHandleMode.RESTART_SINGLE_STEP.getCode();
					operateButtons.put(nameKey, functionCode);
					
					//----重新执行该步骤，并继续跑完所在任务中剩余步骤
					nameKey = ErrBatchHandleMode.RESTART_STEP_JOB_GO_ON.getDesc();
					functionCode = ErrBatchHandleMode.RESTART_STEP_JOB_GO_ON.getCode();
					operateButtons.put(nameKey, functionCode);
					
					//----忽略该步骤，继续执行该批任务后面的剩余步骤
					if(!step.canSkip()){
						//是否可手工跳过
						if(step.canSkipManually()){
							
							nameKey = ErrBatchHandleMode.IGNORE_STEP_JOB_GO_ON.getDesc();
							functionCode = ErrBatchHandleMode.IGNORE_STEP_JOB_GO_ON.getCode();
							operateButtons.put(nameKey, functionCode);
						}
					}
					
					//----只重新执行所属任务
					nameKey = ErrBatchHandleMode.RESTART_SINGLE_JOB.getDesc();
					functionCode = ErrBatchHandleMode.RESTART_SINGLE_JOB.getCode();
					operateButtons.put(nameKey, functionCode);
					
				}else{//不可跳过 或 串行

					/** 运行任务类型为批次任务--job**/
				    if(batchRunningMode == RunningMode.START_SINGLE_JOB){
						//----只重新执行所属任务
						nameKey = ErrBatchHandleMode.RESTART_SINGLE_JOB.getDesc();
						functionCode = ErrBatchHandleMode.RESTART_SINGLE_JOB.getCode();
						operateButtons.put(nameKey, functionCode);
				    }
					
					//step是否可自动跳过
					if(step.canSkip()){
						
						//----只执行该步骤
						nameKey = ErrBatchHandleMode.RESTART_SINGLE_STEP.getDesc();
						functionCode = ErrBatchHandleMode.RESTART_SINGLE_STEP.getCode();
						operateButtons.put(nameKey, functionCode);
					}else{
						
						//是否可手工跳过
						if(step.canSkipManually()){
							
							//----忽略，就绪执行该批次
							nameKey = ErrBatchHandleMode.IGNORE_STEP_GO_ON.getDesc();
							functionCode = ErrBatchHandleMode.IGNORE_STEP_GO_ON.getCode();
							operateButtons.put(nameKey, functionCode);
						}
					}
				    
					//----重新执行该步骤，并继续跑整个批次
					nameKey = ErrBatchHandleMode.RESTART_STEP_GO_ON.getDesc();
					functionCode = ErrBatchHandleMode.RESTART_STEP_GO_ON.getCode();
					operateButtons.put(nameKey, functionCode);
				}
		    }
			//添加到Bean中
		    detail.setOperateButtons(operateButtons);
		}
	}
	
	/**
	 * 构造通过外键的查询SQL语句
	 * @param args
	 */
	public static Map<String, String> buildSqlMapByID(BatchPageTable tableEnum) {
		
		Map<String, String> sqlMap = new HashMap<String, String>();
		/** 获得信息的总数量**/
		StringBuffer countSb = new StringBuffer();
		countSb.append(" Select count(*) From ")
		       .append(tableEnum.getDesc())
		       .append(" Where ")
		       .append(tableEnum.getFkDesc())
		       .append(" = ? ");
		sqlMap.put(BatchSysConstants.COUNT_SQL, countSb.toString());
		
		/** 获得分页数据信息**/
		//要查询数据的SQL
		StringBuffer statSb = new StringBuffer();
		statSb.append(" Select bs.*, rownumber() over(")
			  .append((tableEnum == BatchPageTable.BATCH_EXEC_LOG) ? "ORDER BY END_TIME DESC" : "")
			  .append(") as rowid  from ")
	          .append(tableEnum.getDesc())
	          .append(" bs Where ")
	          .append(tableEnum.getFkDesc())
	          .append(" = ? ");
		//进行分页
		StringBuffer pageSb = new StringBuffer();
		pageSb.append("Select * from ( ")
		      .append(statSb.toString())
		      .append(" ) as a where a.rowid >= ? AND a.rowid <? with ur");
		
		sqlMap.put(BatchSysConstants.PAGE_SQL, pageSb.toString());
		
		return sqlMap;
	}
	
	/**
	 * 构造没有通过外键的查询SQL语句
	 * @param args
	 */
	public static Map<String, String> buildSqlMapNonID(BatchPageTable tableEnum) {
		
		Map<String, String> sqlMap = new HashMap<String, String>();
		/** 获得信息的总数量**/
		StringBuffer countSb = new StringBuffer();
		countSb.append(" Select count(*) From ")
		       .append(tableEnum.getDesc())
		       .append(" WITH UR ");
		sqlMap.put(BatchSysConstants.COUNT_SQL, countSb.toString());
		
		/** 获得分页数据信息**/
		//要查询数据的SQL
		StringBuffer statSb = new StringBuffer();
		statSb.append(" Select bs.*, rownumber() over(")
		      .append((tableEnum == BatchPageTable.BATCH_EXEC_LOG) ? "ORDER BY END_TIME DESC" : "")
		      .append(") as rowid  from ")
	          .append(tableEnum.getDesc())
	          .append(" bs ");
		//进行分页
		StringBuffer pageSb = new StringBuffer();
		pageSb.append("Select * from ( ")
		      .append(statSb.toString())
		      .append(" ) as a where a.rowid >= ? AND a.rowid <? with ur");
		sqlMap.put(BatchSysConstants.PAGE_SQL, pageSb.toString());
		return sqlMap;
	}
	
	/**
	 * 批次拉起方式的类型变为汉字显示
	 */
	public static String runModeToChStr(String modeCode) {
		
		RunningMode mode = RunningMode.parseByCode(modeCode);
		return mode.getDbDesc();
	}
	
	/**
	 * 任务信息的控制符变为汉字显示
	 */
	public static String jobCtrlFlgsToChStr(JobInfo jobInfo) {
		StringBuffer ctrlFlgs = new StringBuffer();
		
		ctrlFlgs.append(jobInfo.isEnabled() ? "启用" : "禁用");
		ctrlFlgs.append("--");
		ctrlFlgs.append(jobInfo.canSkip() ? "可跳过" : "整个批次停止");
		ctrlFlgs.append("--");
		ctrlFlgs.append(jobInfo.isConcurrent() ? "并行" : "串行");
		
		return ctrlFlgs.toString();
	}
	
	/**
	 * 步骤信息的控制符变为汉字显示
	 */
	public static String stepCtrlFlgsToChStr(StepInfo stepInfo) {
		StringBuffer ctrlFlgs = new StringBuffer();
		
		ctrlFlgs.append(stepInfo.isEnabled() ? "启用" : "禁用");
		ctrlFlgs.append("--");
		ctrlFlgs.append(stepInfo.canSkip() ? "可跳过" : "整个任务停止");
		ctrlFlgs.append("--");
		ctrlFlgs.append(stepInfo.canSkipManually() ? "可手动跳过" : "不可手动跳过");
		
		return ctrlFlgs.toString();
	}
	
	/**
	 * 转换批次运行类型变为汉字显示
	 */
	public static String batchRunTypeToStr(String batchRunType) {
		
		BatchRunType type = BatchRunType.parseByCode(batchRunType);
		return type.getDesc();
	}
	
	/**
	 * 转换步骤的运行周期为汉字显示
	 */
	public static String stepRunPeriodToChStr(String period) {
		RunPeriod type = RunPeriod.parseByType(period);
		return type != null ? type.getDesc() : period;
	}
	
	public static void main(String[] args) {
		long now = System.currentTimeMillis();
		for (int i = 0; i < 90; i ++) {
			now = now - 24 * 3600000;
		}
		System.out.println(new Date(now));
		System.out.println(nextDay(new Date(now)));
		System.out.println(preDay(new Date(now)));
		
		System.out.println(formatTimeStamp(new Date()));
	}







}
